﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using Microsoft.Phone.Controls;
using System.Device.Location;
using Microsoft.Phone.Controls.Maps;
using Microsoft.Phone.Shell;
using Microsoft.Phone.Controls.Maps.Platform;
using System.Diagnostics;
using System.Windows.Media.Imaging;
using System.Windows.Threading;
using Microsoft.Phone.Tasks;
using System.Collections.ObjectModel;
using TransportMe.Bing.Route;
using TransportMe.Bing.Geocode;
using TransportMe.Models;
using TransportMe.Helpers;
using System.Threading;
using System.Reflection;

namespace TransportMe
{
    public partial class Home : PhoneApplicationPage
    {
        public GeoCoordinateWatcher watcher;
        private FakeGps gps = new FakeGps();
        private ApplicationBarIconButton btnSettings;
        private Pushpin pinStart;
        public static Pushpin pinEnd;
        private int numberOfPins = 0;
        private DispatcherTimer dt;
        public int cnt = 0;
        private BingMapsDirectionsTask bingMapsDirectionsTask = new BingMapsDirectionsTask();
        private LabeledMapLocation lml;
        private readonly CredentialsProvider credentialsProvider = new ApplicationIdCredentialsProvider("AuDSE0Y4Yup-cjQyUA61BbP8O3zq3w93KsNr7hhMjpZXTS5Bh7wFIswFtk5AMJBs");

        private readonly ObservableCollection<RouteModel> _routes = new ObservableCollection<RouteModel>();
        private readonly ObservableCollection<ItineraryItem> _itineraries = new ObservableCollection<ItineraryItem>();

        private GeocodeResult result1;
        private GeocodeResult result2;
        private ReverseGeocodeRequest request = new ReverseGeocodeRequest();
        private GeocodeServiceClient geocodeService = new GeocodeServiceClient("BasicHttpBinding_IGeocodeService");

        public static LocationCollection listOfLoc = new LocationCollection();

        public ObservableCollection<RouteModel> Routes
        {
            get { return _routes; }
        }

        public ObservableCollection<ItineraryItem> Itineraries
        {
            get { return _itineraries; }
        }

        public string To { get; set; }
        public string From { get; set; }

        public Home()
        {
            InitializeComponent();

            pinStart = new Pushpin();
            pinEnd = new Pushpin();
            pinStart.Content = "Start";
            pinEnd.Content = "End";


           new Nimbus().LoadDataVehicle();
           
	   DateTime dt = new DateTime();
           dt.AddMinutes(450);
           DateTime dt2 = new DateTime();
           dt2.AddMinutes(1290); 
 //create carparks
           CarPark cp1 = new CarPark("carpark1", "HDB Carpark", 1.0, dt, dt2, 103.935065, 1.326595, "nil");
           CarPark cp2 = new CarPark("carpark2", "HDB Carpark", 1.0, dt, dt2, 103.935837, 1.328044, "nil");
           CarPark cp3 = new CarPark("carpark3", "HDB Carpark Bedok Park and Ride", 1.0, dt, dt2, 103.931251, 1.325329, "Bedok");

           CarPark.listOfCarParks.Add(cp1);
           CarPark.listOfCarParks.Add(cp2);
           CarPark.listOfCarParks.Add(cp3);
        }        
	private void PhoneApplicationPage_Loaded(object sender, RoutedEventArgs e)
        {
            CallLocationService();
        }

        public void CallLocationService()
        {
            // The watcher variable was previously declared as type GeoCoordinateWatcher.
            // gps.Start();

            if (watcher == null)
            {
                //watcher = new GeoCoordinateWatcher(GeoPositionAccuracy.High);
                //watcher.MovementThreshold = App.IsolatedStorageCacheManager<double>.Retrieve("thresholdSlider.xml"); // use MovementThreshold to ignore noise in the signal
                //watcher.StatusChanged += new EventHandler<GeoPositionStatusChangedEventArgs>(watcher_StatusChanged);
                //watcher.PositionChanged += new EventHandler<GeoPositionChangedEventArgs<GeoCoordinate>>(watcher_PositionChanged);
            }
            //watcher.Start();

            GeoCoordinate gc;
            switch (numberOfPins)
            {
                case 0:
                    App.L.Latitude = 1.297036; // queen st
                    App.L.Longitude = 103.851407;
                    gc = new GeoCoordinate(App.L.Latitude, App.L.Longitude);

                    map.SetView(gc, 17.5);
                    break;
                case 1:
                    App.L.Latitude = 1.331157; // bedok ave 3
                    App.L.Longitude = 103.932853;
                    gc = new GeoCoordinate(App.L.Latitude, App.L.Longitude);

                    map.SetView(gc, 17.5);
                    break;
                case 2:
                    App.L.Latitude = 1.354955; // millennia institute
                    App.L.Longitude = 103.736435;

                    gc = new GeoCoordinate(App.L.Latitude, App.L.Longitude);

                    map.SetView(gc, 17.5);
                    break;
            }
        }

        public void CallLocationServiceAndPlacePin()
        {
            GeoCoordinate gc;
            switch (numberOfPins)
            {
                case 0:
                    CallLocationService();

                    gc = new GeoCoordinate(App.L.Latitude, App.L.Longitude);
                    pinStart.Location = gc;
                    map.Children.Add(pinStart);
                    numberOfPins++;

                    lml = new LabeledMapLocation("Start", gc);
                    bingMapsDirectionsTask.Start = lml;
                    // bingMapsDirectionsTask.Start is not set. The user’s current location is used as the start point.

                    break;
                case 1:
                    CallLocationService();

                    gc = new GeoCoordinate(App.L.Latitude, App.L.Longitude);
                    pinEnd.Location = gc;
                    map.Children.Add(pinEnd);
                    numberOfPins++;

                    lml = new LabeledMapLocation("End", gc);
                    bingMapsDirectionsTask.End = lml;
                    // bingMapsDirectionsTask.Start is not set. The user’s current location is used as the start point

                    break;
                case 2:
                    CallLocationService();
                    CalculateRoute();

                    break;
            }
        }

        void watcher_PositionChanged(object sender, GeoPositionChangedEventArgs<GeoCoordinate> e)
        {
            //Deployment.Current.Dispatcher.BeginInvoke(() =>
            //{
            //SetMapLocation(e.Position.Location.Latitude, e.Position.Location.Longitude);
            App.L = e.Position.Location;

            GeoCoordinate gc = new GeoCoordinate(App.L.Latitude, App.L.Longitude);
            map.SetView(gc, 10);

            watcher.Stop();
            //watcher = null;
            //});

        }

        void watcher_StatusChanged(object sender, GeoPositionStatusChangedEventArgs e)
        {
            switch (e.Status)
            {
                case GeoPositionStatus.Disabled:
                    // The Location Service is disabled or unsupported.
                    // Check to see if the user has disabled the Location Service.
                    if (watcher.Permission == GeoPositionPermission.Denied)
                    {
                        // The user has disabled the Location Service on their device.
                        //statusTextBlock.Text = "you have this application access to location.";
                        MessageBox.Show("Your Location Service is disabled or unsupported. \n\nYou can enable it by exiting from this app and turning it on in your phone Settings page");
                    }
                    break;

                case GeoPositionStatus.Initializing:
                    // The Location Service is initializing.
                    // Disable the Start Location button.
                    //startLocationButton.IsEnabled = false;
                    //progressBar1.Visibility = System.Windows.Visibility.Visible;
                    //MessageBox.Show("Watcher initializing");
                    break;

                case GeoPositionStatus.NoData:
                    // The Location Service is working, but it cannot get location data.
                    // Alert the user and enable the Stop Location button.
                    //statusTextBlock.Text = "location data is not available.";
                    //stopLocationButton.IsEnabled = true;
                    //MessageBox.Show("Watcher no data");
                    // CHRIS: Happens briefly on initial stages of getting location
                    //if (!loadNearbylist)
                    //{
                    //MessageBox.Show("Your Location service is available but cannot get location data");
                    //mainPageStatusTextBlock.Text = "";
                    //checkBoxLocation.IsChecked = false;
                    //}
                    break;

                //called everytime watcher is restarted
                case GeoPositionStatus.Ready:
                    // The Location Service is working and is receiving location data.
                    // Show the current position and enable the Stop Location button.
                    //statusTextBlock.Text = "location data is available.";
                    //stopLocationButton.IsEnabled = true;
                    //if (progressBar1.Visibility == System.Windows.Visibility.Visible)
                    //{
                    //    progressBar1.Visibility = System.Windows.Visibility.Collapsed;
                    //};
                    //MessageBox.Show("Hello");
                    //SetupPushNotification();
                    //MessageBox.Show("Watcher ready");
                    break;
            }
        }

 

        private void btnFind_Click(object sender, RoutedEventArgs e)
        {
            CallLocationService();
        }

        private void PlantPin(Pushpin p, Location l)
        {
            p.Location = l;
            map.Children.Add(p);
        }

        private void map_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            //Debug.WriteLine("Hi");
            //Change the Clickmode to Press, add a dispatchTimer and a method to catch the press event which begins the timer, a counter for your timer ticks and a method call inside the tick if you hit your counter criteria.  But note that the press event will be triggered in a “press and release” scenario as well
        }

        private void imgStart_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            CallLocationServiceAndPlacePin();

            switch (numberOfPins)
            {
                case 1:
                    imgStart.Source = new BitmapImage(new Uri("Images/Pushpin-End.png", UriKind.Relative));
                    break;
                case 2:
                    imgStart.Source = new BitmapImage(new Uri("Images/Calc.png", UriKind.Relative));
                    break;
            }
        }

        private void imgStart_ImageFailed(object sender, ExceptionRoutedEventArgs e)
        {
            // do nothing
        }

        //private void StartHoldTimer()
        //{
        //    dt = new DispatcherTimer();
        //    dt.Interval = new TimeSpan(0, 0, 0, 0, 500);// 500 Milliseconds
        //    dt.Tick += new EventHandler(dt_Tick);
        //    dt.Start();
        //}

        private void map_Hold(object sender, System.Windows.Input.GestureEventArgs e)
        {
            switch (numberOfPins)
            {
                case 0:
                    if (MessageBox.Show("Add start point", "Start", MessageBoxButton.OKCancel) == MessageBoxResult.OK)
                    {
                        var position = e.GetPosition(map);
                        var location = map.ViewportPointToLocation(position);
                        pinStart.Location = location;
                        map.Children.Add(pinStart);
                        numberOfPins++;
                        imgStart.Source = new BitmapImage(new Uri("Images/Pushpin-End.png", UriKind.Relative));
                    }
                    break;
                case 1:
                    if (MessageBox.Show("Add end point", "End", MessageBoxButton.OKCancel) == MessageBoxResult.OK)
                    {
                        var position = e.GetPosition(map);
                        var location = map.ViewportPointToLocation(position);
                        pinEnd.Location = location;
                        map.Children.Add(pinEnd);
                        numberOfPins++;
                        imgStart.Source = new BitmapImage(new Uri("Images/Calc.png", UriKind.Relative));
                    }
                    break;
                case 2:
                    if (MessageBox.Show("Change end point?", "End", MessageBoxButton.OKCancel) == MessageBoxResult.OK)
                    {
                        map.Children.Remove(pinEnd);
                        var position = e.GetPosition(map);
                        var location = map.ViewportPointToLocation(position);
                        pinEnd.Location = location;
                        map.Children.Add(pinEnd);
                    }
                    break;
            }
        }

        private void geocodeService_ReverseGeocodeCompleted(object sender, ReverseGeocodeCompletedEventArgs e)
        {
            result1 = new GeocodeResult();
            result1 = e.Result.Results[0];

            request.Location = pinEnd.Location;

            geocodeService.ReverseGeocodeCompleted -= geocodeService_ReverseGeocodeCompleted;
            geocodeService.ReverseGeocodeCompleted += new EventHandler<ReverseGeocodeCompletedEventArgs>(geocodeService_ReverseGeocodeCompleted2);

            geocodeService.ReverseGeocodeAsync(request);
        }

        private void geocodeService_ReverseGeocodeCompleted2(object sender, ReverseGeocodeCompletedEventArgs e)
        {
            result2 = new GeocodeResult();
            result2 = e.Result.Results[0];

            To = result1.DisplayName.ToString();
            From = result2.DisplayName.ToString();

            try
            {
                var routeCalculator = new RouteCalculator(
                    credentialsProvider,
                    To,
                    From,
                    Dispatcher,
                    result =>
                    {
                        // Clear the route collection to have only one route at a time.
                        Routes.Clear();

                        // Clear previous route related itineraries.
                        Itineraries.Clear();

                        // Create a new route based on route calculator result,
                        // and add the new route to the route collection.
                        var routeModel = new RouteModel(result.Result.RoutePath.Points);
                        Routes.Add(routeModel);

                        // Add new route itineraries to the itineraries collection.
                        foreach (var itineraryItem in result.Result.Legs[0].Itinerary)
                        {
                            Itineraries.Add(itineraryItem);
                        }

                        // Set the map to center on the new route.
                        var viewRect = LocationRect.CreateLocationRect(routeModel.Locations);
                        map.SetView(viewRect);

                        MapPolyline line = new MapPolyline();
                        line.Locations = new LocationCollection();
                        foreach (GeoCoordinate gc in routeModel.Locations)
                        {
                            Location l = new Location();
                            l.Altitude = gc.Altitude;
                            l.Longitude = gc.Longitude;
                            l.Latitude = gc.Latitude;
                            line.Locations.Add(l);
                        }

                        listOfLoc = line.Locations;
                        map.Children.Add(line);
                        SolidColorBrush brush = new SolidColorBrush(Color.FromArgb(255, 255, 0, 155));
                        line.Stroke = brush;
                        line.StrokeThickness = 6.0;
                        line.Opacity = 0.75;
                        line.Visibility = Visibility.Visible;

                        double totalDistance = 0;
                        foreach (ItineraryItem i in Itineraries)
                        {
                            totalDistance += i.Summary.Distance;
                        }
                        App.Distance = totalDistance * 1.609344;
                        NavigationService.Navigate(new Uri("/Calculator.xaml", UriKind.Relative));
                    });
                // Display an error message in case of fault.
                routeCalculator.Error += r => MessageBox.Show(r.Reason);

                // Start the route calculation asynchronously.
                routeCalculator.CalculateAsync();
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }

        private void CalculateRoute()
        {
            Credentials c = new Credentials();
            c.ApplicationId = "AuDSE0Y4Yup-cjQyUA61BbP8O3zq3w93KsNr7hhMjpZXTS5Bh7wFIswFtk5AMJBs";
            request.Credentials = c;
            request.Location = pinStart.Location;

            result1 = null;
            result2 = null;

            // Make the reverse geocode request
            geocodeService = new GeocodeServiceClient("BasicHttpBinding_IGeocodeService");
            geocodeService.ReverseGeocodeCompleted += new EventHandler<ReverseGeocodeCompletedEventArgs>(geocodeService_ReverseGeocodeCompleted);
            geocodeService.ReverseGeocodeAsync(request);
        }

        private void imgClear_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            if (MessageBox.Show("Clear all locations?", "Clear", MessageBoxButton.OKCancel) == MessageBoxResult.OK)
            {
                map.Children.Remove(pinStart);
                map.Children.Remove(pinEnd);

                numberOfPins = 0;
                imgStart.Source = new BitmapImage(new Uri("Images/Pushpin-Start.png", UriKind.Relative));
            }
        }

        private void imgFind_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            CallLocationService();
        }

        private void pushpin_Hold(object sender, System.Windows.Input.GestureEventArgs e)
        {
            if (MessageBox.Show("Clear map point?", "Clear", MessageBoxButton.OKCancel) == MessageBoxResult.OK)
            {
                Pushpin p = (Pushpin)e.OriginalSource;
                map.Children.Remove(p);
                numberOfPins--;
            }
            switch (numberOfPins)
            {
                case 1:
                    imgStart.Source = new BitmapImage(new Uri("Images/Pushpin-End.png", UriKind.Relative));
                    break;
                case 0:
                    imgStart.Source = new BitmapImage(new Uri("Images/Pushpin-Start.png", UriKind.Relative));
                    break;
            }
        }
    }
}
